﻿using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
using UnityEditor.IMGUI.Controls;
using System;
using System.Linq;

namespace AssetTools
{
    public class ReferenceFinderWindow : EditorWindow
    {
        //依赖模式的key
        const string isDependPrefKey = "ReferenceFinderData_IsDepend";
        //是否需要更新信息状态的key
        const string needUpdateStatePrefKey = "ReferenceFinderData_needUpdateState";

        private static ReferenceFinderData data = new ReferenceFinderData();

        private bool isDepend = false;
        private bool needUpdateState = true;
        private string sortButtonText = "Sort:";

        private bool needUpdateAssetTree = false;
        private bool initializedGUIStyle = false;
        //工具栏按钮样式
        private GUIStyle toolbarButtonGUIStyle;
        //工具栏样式
        private GUIStyle toolbarGUIStyle;
        //提示标签样式
        private GUIStyle labelGUIStyle;
        //选中资源列表
        private List<string> selectedAssetGuid = new List<string>();

        private AssetTreeView m_AssetTreeView;

        [SerializeField]
        private TreeViewState m_TreeViewState;

        private EventCenter eventCenter;

        DeleteWindow deleteWindow;

        //要删除的资源
        List<AssetViewItem> m_DeleteAssets = new List<AssetViewItem>();

        //查找资源引用信息
        [MenuItem("Assets/Find References In Project (Ctrl+Shift+Z)", false, 45)]
        [MenuItem("Tools/Find References In Project %#z", false, 0)]
        static void FindRef()
        {
            ReferenceFinderWindow window = GetWindow<ReferenceFinderWindow>();
            window.wantsMouseMove = false;
            window.titleContent = new GUIContent("Ref Finder");
            window.Show();
            window.Focus();

            window.CreateEventCenter();
            window.UpdateSelectedAssets();
        }

        //初始化GUIStyle
        void InitGUIStyleIfNeeded()
        {
            if (!initializedGUIStyle)
            {
                toolbarButtonGUIStyle = new GUIStyle("ToolbarButton");
                toolbarGUIStyle = new GUIStyle("Toolbar");
                labelGUIStyle = new GUIStyle("label");
                labelGUIStyle.fontStyle = FontStyle.Bold;
                labelGUIStyle.fontSize = 15;
                initializedGUIStyle = true;
            }
        }

        void CreateEventCenter()
        {
            eventCenter = new EventCenter();
            eventCenter.AddEventListener(0, OpenDeleteWindow);
            eventCenter.AddEventListener(1, OpenDeleteWindowViaRecursive);
            eventCenter.AddEventListener(2, DeleteAssetDetermine);
            eventCenter.AddEventListener(3, SelectAVIsExpand);
            eventCenter.AddEventListener(4, SelectAVIsCollapses);
            eventCenter.AddEventListener(5, SelectAVIsEliminate);
        }

        //更新选中资源列表
        private void UpdateSelectedAssets()
        {
            selectedAssetGuid.Clear();
            foreach (var obj in Selection.objects)
            {
                string path = AssetDatabase.GetAssetPath(obj);

                //如果选中的是Hierarchy里面的对象的话就通过路径判断来中止
                if (string.IsNullOrEmpty(path))
                    continue;

                //如果是文件夹
                if (Directory.Exists(path))
                {
                    string[] folder = new string[] { path };
                    //将文件夹下所有资源作为选择资源
                    string[] guids = AssetDatabase.FindAssets(null, folder);
                    foreach (var guid in guids)
                    {
                        if (!selectedAssetGuid.Contains(guid) &&
                            !Directory.Exists(AssetDatabase.GUIDToAssetPath(guid)))
                        {
                            selectedAssetGuid.Add(guid);
                        }
                    }
                }
                //如果是文件资源
                else
                {
                    string guid = AssetDatabase.AssetPathToGUID(path);
                    selectedAssetGuid.Add(guid);
                }
            }
            needUpdateAssetTree = true;
        }

        //通过选中资源列表更新TreeView
        private void UpdateAssetTree()
        {
            if (needUpdateAssetTree && selectedAssetGuid.Count != 0)
            {
                var root = SelectedAssetGuidToRootItem(selectedAssetGuid);
                if (m_AssetTreeView == null)
                {
                    //初始化TreeView
                    if (m_TreeViewState == null)
                        m_TreeViewState = new TreeViewState();
                    var headerState = AssetTreeView.CreateDefaultMultiColumnHeaderState(position.width);
                    var multiColumnHeader = new MultiColumnHeader(headerState);
                    m_AssetTreeView = new AssetTreeView(m_TreeViewState, multiColumnHeader, eventCenter);
                }
                m_AssetTreeView.assetRoot = root;
                m_AssetTreeView.CollapseAll();
                m_AssetTreeView.Reload();
                needUpdateAssetTree = false;
            }
        }

        private void OnEnable()
        {
            isDepend = PlayerPrefs.GetInt(isDependPrefKey, 0) == 1;
            needUpdateState = PlayerPrefs.GetInt(needUpdateStatePrefKey, 1) == 1;
        }

        private void OnGUI()
        {
            InitGUIStyleIfNeeded();
            DrawOptionBar();

            Rect rect = this.position;
            float x = (rect.width / 3.5f);
            float y = (rect.height / 2);
            //判断有无资源信息缓存文件
            if (!data.CACHEFileExists)
            {
                Rect rect1 = new Rect(x, y, 400, 100);
                GUILayout.BeginArea(rect1);
                GUILayout.Label("No FromCache,Click \"Refresh Data\" Button", labelGUIStyle);
                GUILayout.EndArea();
                return;
            }
            //判断有无选择资源
            if (selectedAssetGuid.Count < 1)
            {
                Rect rect1 = new Rect(x, y, 400, 300);
                GUILayout.BeginArea(rect1);
                GUILayout.Label("No Select Assets To Display", labelGUIStyle);
                GUILayout.Label("1.Select Assets", labelGUIStyle);
                GUILayout.Label("2.Press \"Ctrl+Shift+Z\" ", labelGUIStyle);
                GUILayout.EndArea();
                return;
            }

            UpdateAssetTree();
            if (m_AssetTreeView != null)
            {
                //绘制Treeview
                m_AssetTreeView.OnGUI(new Rect(0, toolbarGUIStyle.fixedHeight, position.width, position.height - toolbarGUIStyle.fixedHeight));
            }

            //处理选中资源项的右键菜单
            //var e = Event.current;
            //if (null != e)
            //{
            //    if (e.type == EventType.MouseDown && e.button == 1)
            //    {
            //        GenericMenu genericMenu = new GenericMenu();
            //        genericMenu.AddItem(new GUIContent("删除资源"),false, DeleteAssetsByRightClick);
            //        genericMenu.ShowAsContext();
            //    }
            //}
        }

        //绘制上条
        public void DrawOptionBar()
        {
            EditorGUILayout.BeginHorizontal(toolbarGUIStyle);
            //刷新数据
            if (GUILayout.Button("Refresh Data", toolbarButtonGUIStyle))
            {
                data.CollectDependenciesInfo();
                needUpdateAssetTree = true;
                EditorGUIUtility.ExitGUI();
            }
            //修改模式
            bool PreIsDepend = isDepend;
            isDepend = GUILayout.Toggle(isDepend, isDepend ? "Depend" : "Reference", toolbarButtonGUIStyle, GUILayout.Width(100));
            if (PreIsDepend != isDepend)
            {
                needUpdateAssetTree = true;
                PlayerPrefs.SetInt(isDependPrefKey, isDepend ? 1 : 0);
            }
            //是否需要更新状态
            bool PreNeedUpdateState = needUpdateState;
            needUpdateState = GUILayout.Toggle(needUpdateState, "Need Update State", toolbarButtonGUIStyle);
            if (PreNeedUpdateState != needUpdateState)
            {
                PlayerPrefs.SetInt(needUpdateStatePrefKey, needUpdateState ? 1 : 0);
            }

            //排序方式
            Rect createBtnRect = GUILayoutUtility.GetRect(new GUIContent("Sort"), toolbarButtonGUIStyle, GUILayout.Width(90));
            if (GUI.Button(createBtnRect, sortButtonText, EditorStyles.toolbarDropDown))
            {
                GenericMenu menu = new GenericMenu();
                AddItemForSortButton(menu);
                menu.DropDown(createBtnRect);
            }


            GUILayout.FlexibleSpace();

            //扩展
            if (GUILayout.Button("Expand", toolbarButtonGUIStyle))
            {
                if (m_AssetTreeView != null) m_AssetTreeView.ExpandAll();
            }
            //折叠
            if (GUILayout.Button("Collapse", toolbarButtonGUIStyle))
            {
                if (m_AssetTreeView != null) m_AssetTreeView.CollapseAll();
            }
            EditorGUILayout.EndHorizontal();
        }

        //生成root相关
        private HashSet<string> updatedAssetSet = new HashSet<string>();
        //通过选择资源列表生成TreeView的根节点
        private AssetViewItem SelectedAssetGuidToRootItem(List<string> selectedAssetGuid)
        {
            updatedAssetSet.Clear();
            int elementCount = 0;
            var root = new AssetViewItem { id = elementCount, depth = -1, displayName = "Root", data = null };//深度指的是此项具有的父级数量,不参与显示的根所以深度是-1
            int depth = 0;
            var stack = new Stack<string>();
            foreach (var childGuid in selectedAssetGuid)
            {
                var child = CreateTree(childGuid, ref elementCount, depth, stack);
                if (child != null)
                    root.AddChild(child); //每个选中的资源都是Root的子节点
            }
            updatedAssetSet.Clear();
            return root;
        }
        //通过每个节点的数据生成子树
        private AssetViewItem CreateTree(string guid, ref int elementCount, int _depth, Stack<string> stack)
        {
            if (stack.Contains(guid))
                return null;

            //如果guid这个资源不在资源字典里面则不需要选择更新按钮也要更新资源状态
            ReferenceFinderData.AssetDescription referenceDataAD;
            if (!data.assetDict.TryGetValue(guid, out referenceDataAD) || ((needUpdateState && !updatedAssetSet.Contains(guid))))
            {
                data.UpdateAssetState(guid);
                updatedAssetSet.Add(guid);
            }
            referenceDataAD = data.assetDict[guid];
            stack.Push(guid);

            //递归生成子树
            ++elementCount;
            var root = new AssetViewItem { id = elementCount, displayName = referenceDataAD.name, data = referenceDataAD, depth = _depth };
            var childGuids = isDepend ? referenceDataAD.dependencies : referenceDataAD.references;
            foreach (var childGuid in childGuids)
            {
                var child = CreateTree(childGuid, ref elementCount, _depth + 1, stack);
                if (child != null)
                    root.AddChild(child);
            }

            stack.Pop();
            return root;
        }

        #region 排序

        //添加排序子菜单
        void AddItemForSortButton(GenericMenu menu)
        {
            string useSort = "Sort: Use";
            string unUseSort = "Sort: UnUse";

            menu.AddItem(new GUIContent(useSort), sortButtonText.Equals(useSort), OnSortButtonSelected, useSort);
            menu.AddItem(new GUIContent(unUseSort), sortButtonText.Equals(unUseSort), OnSortButtonSelected, unUseSort);

        }

        //点击排序按钮的回调
        void OnSortButtonSelected(object isSelected)
        {
            sortButtonText = (string)isSelected;

            List<string> selectedAssetGuidByUnUseSort = new List<string>(); //被使用的资源
            List<string> selectedAssetGuidByUseSort = new List<string>();  //未被使用的资源
            List<string> SAGuidBySort = new List<string>();

            for (int i = 0; i < selectedAssetGuid.Count; i++)
            {
                ReferenceFinderData.AssetDescription ad;
                if (!data.assetDict.TryGetValue(selectedAssetGuid[i], out ad))
                {
                    var path = AssetDatabase.GUIDToAssetPath(selectedAssetGuid[i]);
                    Debug.LogWarning(path + "not exist in Cache,click \"Refresh Data\" button fitst");
                    continue;
                }

                if ((isDepend && ad.dependencies.Count < 1) || (!isDepend && ad.references.Count < 1))
                    selectedAssetGuidByUnUseSort.Add(selectedAssetGuid[i]);
                else
                    selectedAssetGuidByUseSort.Add(selectedAssetGuid[i]);
            }

            //根据未使用的资源进行排序
            if (sortButtonText.Equals("Sort: UnUse"))
            {
                for (int i = 0; i < selectedAssetGuidByUnUseSort.Count; i++)
                {
                    SAGuidBySort.Add(selectedAssetGuidByUnUseSort[i]);
                }
                for (int i = 0; i < selectedAssetGuidByUseSort.Count; i++)
                {
                    SAGuidBySort.Add(selectedAssetGuidByUseSort[i]);
                }
            }
            if (sortButtonText.Equals("Sort: Use"))
            {
                for (int i = 0; i < selectedAssetGuidByUseSort.Count; i++)
                {
                    SAGuidBySort.Add(selectedAssetGuidByUseSort[i]);
                }
                for (int i = 0; i < selectedAssetGuidByUnUseSort.Count; i++)
                {
                    SAGuidBySort.Add(selectedAssetGuidByUnUseSort[i]);
                }
            }
            //重新绘制
            selectedAssetGuid = SAGuidBySort;
            needUpdateAssetTree = true;
            UpdateAssetTree();
        }

        #endregion

        #region 删除

        /// <summary>
        /// 删除资源按钮的回调,打开删除窗口
        /// </summary>
        public void OpenDeleteWindow(object userData)
        {
            var temp = (AssetViewItem[])userData;
            m_DeleteAssets = temp.ToList();

            if (deleteWindow == null)
            {
                deleteWindow = CreateInstance<DeleteWindow>();
                deleteWindow.ShowPopup();
                deleteWindow.position = new Rect(Screen.width / 2, Screen.height / 2, 600, 440);
                deleteWindow.Focus();

                string[] path = new string[m_DeleteAssets.Count];
                for (int i = 0; i < m_DeleteAssets.Count; i++)
                {
                    path[i] = m_DeleteAssets[i].data.path;
                }
                deleteWindow.InitWindow(path, eventCenter);
            }
        }

        /// <summary>
        /// 删除包括子项资源按钮的回调,打开删除窗口
        /// </summary>
        public void OpenDeleteWindowViaRecursive(object userData)
        {
            var m_AVIs = (AssetViewItem[])userData;
            for (int i = 0; i < m_AVIs.Length; i++)
            {
                FindRecursiveAVIs(m_AVIs[i]);
            }

            if (deleteWindow == null)
            {
                deleteWindow = CreateInstance<DeleteWindow>();
                deleteWindow.ShowPopup();
                deleteWindow.position = new Rect(Screen.width / 2, Screen.height / 2, 600, 440);
                deleteWindow.Focus();

                string[] path = new string[m_DeleteAssets.Count];
                for (int i = 0; i < m_DeleteAssets.Count; i++)
                {
                    path[i] = m_DeleteAssets[i].data.path;
                }
                deleteWindow.InitWindow(path, eventCenter);
            }
        }

        public void FindRecursiveAVIs(AssetViewItem AVItem)
        {
            var childGuids = isDepend ? AVItem.data.dependencies : AVItem.data.references;
            foreach (var childGuid in childGuids)
            {
                ReferenceFinderData.AssetDescription referenceDataAD;
                if (data.assetDict.TryGetValue(childGuid, out referenceDataAD))
                    FindRecursiveAVIs(new AssetViewItem { data = referenceDataAD });
            }

            //可能把父项和子项都选中了，或者一个资源多次选中
            for (int i = 0; i < m_DeleteAssets.Count; i++)
            {
                if (m_DeleteAssets[i].data.path == AVItem.data.path)
                    return;
            }
            m_DeleteAssets.Add(AVItem);
        }

        /// <summary>
        /// 确定删除资源的回调
        /// </summary>
        public void DeleteAssetDetermine(object userData)
        {
            bool delete = (bool)userData;
            if (delete)
            {
                if (m_DeleteAssets.Count < 1 || m_DeleteAssets == null)
                    return;

                //删除资源
                for (int i = 0; i < m_DeleteAssets.Count; i++)
                {
                    AssetViewItem AVI = m_DeleteAssets[i];
                    AssetDatabase.DeleteAsset(AVI.data.path);
                    AssetDatabase.Refresh();
                }

                //重新绘制GUI
                for (int i = 0; i < m_DeleteAssets.Count; i++)
                {
                    AssetViewItem item = m_DeleteAssets[i];

                    for (int j = 0; j < selectedAssetGuid.Count; j++)
                    {
                        if (selectedAssetGuid[j] == AssetDatabase.AssetPathToGUID(item.data.path))
                        {
                            selectedAssetGuid.Remove(AssetDatabase.AssetPathToGUID(item.data.path));
                        }
                    }
                }

                needUpdateAssetTree = true;
                UpdateAssetTree();
            }

            m_DeleteAssets.Clear();
        }

        private void OnFocus()
        {
            if (deleteWindow != null)
            {
                deleteWindow.Focus();
            }
        }
        #endregion

        #region 对选中的资源项展开和合并
        private void SelectAVIsExpand(object userData)
        {
            AssetViewItem[] selectAVIs = (AssetViewItem[])userData;
            for (int i = 0; i < selectAVIs.Length; i++)
            {
                //m_AssetTreeView.SetExpanded(selectAVIs[i].id, true);
                m_AssetTreeView.SetExpandedRecursive(selectAVIs[i].id, true);
            }
        }

        private void SelectAVIsCollapses(object userData)
        {
            AssetViewItem[] selectAVIs = (AssetViewItem[])userData;
            for (int i = 0; i < selectAVIs.Length; i++)
            {
                //m_AssetTreeView.SetExpanded(selectAVIs[i].id,false);
                m_AssetTreeView.SetExpandedRecursive(selectAVIs[i].id, false);
            }
        }
        #endregion

        #region 剔除选择的资源项
        private void SelectAVIsEliminate(object userData)
        {
            AssetViewItem[] selectAVIs = (AssetViewItem[])userData;
            for (int i = 0; i < selectAVIs.Length; i++)
            {
                AssetViewItem item = selectAVIs[i];

                for (int j = 0; j < selectedAssetGuid.Count; j++)
                {
                    if (selectedAssetGuid[j] == AssetDatabase.AssetPathToGUID(item.data.path))
                    {
                        selectedAssetGuid.Remove(AssetDatabase.AssetPathToGUID(item.data.path));
                    }
                }
            }

            needUpdateAssetTree = true;
            UpdateAssetTree();
        }

        #endregion
    }
}